package git.soulbgm.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import git.soulbgm.common.base.BaseController;
import git.soulbgm.common.okhttp.OkHttpUtil;
import git.soulbgm.common.pojo.QueryDto;
import git.soulbgm.common.pojo.Response;
import git.soulbgm.pojo.NodeInfo;
import git.soulbgm.pojo.ServiceInfo;
import git.soulbgm.pojo.dto.FileInfoDto;
import git.soulbgm.service.NodeInfoService;
import git.soulbgm.service.ServiceInfoService;
import git.soulbgm.service.ServiceStatusService;
import git.soulbgm.utils.EasyPoiUtil;
import git.soulbgm.utils.StringUtil;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import static git.soulbgm.common.MonitorConstants.*;

/**
 * 服务信息控制器
 *
 * @author SoulBGM
 * @date 2022/03/11 10:28
 */
@RestController
@RequestMapping("system/service")
public class ServiceController extends BaseController {

    private final ServiceInfoService serviceInfoService;
    private final ServiceStatusService serviceStatusService;
    private final NodeInfoService nodeInfoService;

    public ServiceController(ServiceInfoService serviceInfoService, ServiceStatusService serviceStatusService, NodeInfoService nodeInfoService) {
        this.serviceInfoService = serviceInfoService;
        this.serviceStatusService = serviceStatusService;
        this.nodeInfoService = nodeInfoService;
    }

    @PostMapping("list")
    public Response list(@RequestBody QueryDto<ServiceInfo> dto, Page<ServiceInfo> queryPage) {
        Page<ServiceInfo> resultPage = serviceInfoService.page(queryPage, new QueryWrapper<>(dto.getData()));
        return success(resultPage);
    }

    @GetMapping("export")
    public void export(ServiceInfo info, HttpServletResponse response) {
        List<ServiceInfo> list = serviceInfoService.list(new QueryWrapper<>(info));
        try {
            EasyPoiUtil.exportExcel(response, "服务数据", list, ServiceInfo.class);
        } catch (IOException e) {
            throw new RuntimeException("导出失败");
        }
    }

    @PostMapping("add")
    public Response add(ServiceInfo info) {
        boolean result = serviceInfoService.save(info);
        if (result) {
            serviceInfoService.clearCache();
        }
        return result ? success() : error();
    }

    @PostMapping("remove")
    public Response remove(String ids) {
        boolean result = serviceInfoService.removeByIds(Arrays.asList(ids.split(",")));
        if (result) {
            serviceStatusService.removeByIds(Arrays.asList(ids.split(",")));
            serviceInfoService.clearCache();
        }
        return result ? success() : error();
    }

    @PostMapping({"changeStatus", "changeSelfStatus", "edit"})
    public Response edit(ServiceInfo info) {
        boolean result = serviceInfoService.updateById(info);
        if (result) {
            serviceInfoService.clearCache();
        }
        return result ? success() : error();
    }

    @PostMapping("getServiceLogList")
    public Response getServiceLogList(ServiceInfo info) {
        Integer serviceCode = info.getServiceCode();
        Integer nodeCode = info.getNodeCode();
        ServiceInfo serviceInfo = getServiceInfo(serviceCode, nodeCode);
        if (serviceInfo == null) {
            return error(StringUtil.format("表中没有服务编号({}), 节点编号({})的服务信息", serviceCode, nodeCode));
        }
        NodeInfo nodeInfo = getNodeInfo(nodeCode);
        if (nodeInfo == null) {
            return error(StringUtil.format("表中没有节点编号({})的节点信息", nodeCode));
        }
        List<FileInfoDto> logList = getLogList(nodeInfo.getIp(), nodeInfo.getPort(), serviceInfo.getLogPath(), SHELL_LL);
        return success(logList);
    }

    private ServiceInfo getServiceInfo(Integer serviceCode, Integer nodeCode) {
        return serviceInfoService.getOne(new LambdaQueryWrapper<ServiceInfo>()
                .eq(ServiceInfo::getServiceCode, serviceCode)
                .eq(ServiceInfo::getNodeCode, nodeCode));
    }

    private NodeInfo getNodeInfo(Integer nodeCode) {
        return nodeInfoService.getOne(new LambdaQueryWrapper<NodeInfo>()
                .eq(NodeInfo::getNodeCode, nodeCode));
    }

    private static final String CANNOT_ACCESS_MSG = "ls: ";

    /**
     * 获取日志列表
     *
     * @param ip      ip
     * @param port    端口
     * @param logPath 日志路径
     * @param format  格式字符串
     * @return {@link List}<{@link FileInfoDto}>
     */
    private static List<FileInfoDto> getLogList(String ip, Integer port, String logPath, String format) {
        String result = getExecResult(ip, port, StringUtil.format(format, logPath));
        if (result.contains(CANNOT_ACCESS_MSG)) {
            return Collections.emptyList();
        }
        return Arrays.stream(result.split("\n")).map(FileInfoDto::new).collect(Collectors.toList());
    }

    /**
     * 获取远程执行结果
     *
     * @param ip      ip
     * @param port    端口
     * @param command 命令
     * @return {@link String}
     */
    private static String getExecResult(String ip, Integer port, String command) {
        String url = StringUtil.format("http://{}:{}{}", ip, port, EXEC_URL);
        return OkHttpUtil.post(url, Collections.singletonMap("command", command));
    }

}
